---
title: 콘텐츠 컬렉션
description: >-
  타입 안전성을 갖춘 콘텐츠 관리
i18nReady: true
---
import { FileTree, CardGrid, LinkCard, Steps } from '@astrojs/starlight/components';
import Since from '~/components/Since.astro'
import RecipeLinks from "~/components/RecipeLinks.astro"
import Badge from "~/components/Badge.astro"
import ReadMore from "~/components/ReadMore.astro"

<p><Since v="2.0.0" /></p>

**콘텐츠 컬렉션**은 모든 Astro 프로젝트에서 콘텐츠 세트를 관리하는 가장 좋은 방법입니다. 컬렉션은 문서를 구성 및 쿼리하고, 편집기에서 자동 완성 및 타입 검사를 활성화하고, 모든 콘텐츠에 대해 TypeScript 타입 안전성을 제공하는 데 도움이 됩니다.
Astro v5.0에서는 콘텐츠 컬렉션을 정의하고 쿼리하기 위한 Content Layer API가 도입되었습니다. 이 확장 가능한 고성능 API는 로컬 컬렉션을 위한 내장 콘텐츠 로더를 제공합니다. 원격 콘텐츠의 경우 타사 및 커뮤니티에서 구축한 로더를 사용하거나 자체 사용자 지정 로더를 만들어 모든 소스에서 데이터를 가져올 수 있습니다.

:::note
프로젝트는 Astro v2.0에 도입된 레거시 콘텐츠 컬렉션 API를 계속 사용할 수 있습니다. 그러나 가능하면 [기존 컬렉션을 업데이트](/ko/guides/upgrade-to/v5/#레거시-v20-콘텐츠-컬렉션-api)하는 것이 좋습니다.
:::

## 콘텐츠 컬렉션이란 무엇입니까?

구조적으로 유사한 데이터 집합에서 **컬렉션**을 정의할 수 있습니다. 블로그 게시물의 디렉터리, 제품 항목의 JSON 파일 또는 동일한 모양의 여러 항목을 나타내는 모든 데이터가 여기에 해당할 수 있습니다.

프로젝트 또는 파일 시스템에 로컬로 저장된 컬렉션에는 Markdown, MDX, Markdoc, YAML, TOML 또는 JSON 파일 항목이 있을 수 있습니다:

<FileTree>
- src/
- **newsletter/** "newsletter" 컬렉션
  - week-1.md 컬렉션 항목
  - week-2.md 컬렉션 항목
  - week-3.md 컬렉션 항목
- **authors/** "author" 컬렉션
  - authors.json 모든 컬렉션 항목이 포함된 단일 파일
</FileTree>

적절한 컬렉션 로더를 사용하면 CMS, 데이터베이스, 헤드리스 결제 시스템 등 모든 외부 소스에서 원격 데이터를 가져올 수 있습니다.

## 컬렉션을 위한 TypeScript 구성

콘텐츠 컬렉션은 편집기에서 Zod 유효성 검사, 자동 완성 및 타입 검사를 제공하기 위해 TypeScript에 의존합니다. Astro의 TypeScript 설정을 `strict` 또는 `strictest` 중 하나로 확장하지 않는 경우 `tsconfig.json`에 다음 `compilerOptions`이 설정되어 있는지 확인해야 합니다:

```json title="tsconfig.json" ins={5} {6}
{
  // "astro/tsconfigs/strict" 또는 "astro/tsconfigs/strictest"에 포함
  "extends": "astro/tsconfigs/base",
  "compilerOptions": {
    "strictNullChecks": true, // `base` 템플릿을 사용하는 경우 추가
    "allowJs": true // 필수, 모든 Astro 템플릿에 포함
  }
}
```

## 컬렉션 정의

개별 컬렉션은 `defineCollection()`을 사용하여 구성합니다:
- 데이터 소스를 위한 `loader`(필수)
- 타입 안전을 위한 `schema`(선택 사항이지만 적극 권장!) 

### 컬렉션 구성 파일

컬렉션을 정의하려면 프로젝트에 `src/content.config.ts` 파일을 만들어야 합니다(`.js` 및 `.mjs` 확장자도 지원됨). 이 파일은 Astro가 다음 구조에 따라 콘텐츠 컬렉션을 구성하는 데 사용하는 특수 파일입니다:

```ts title="src/content.config.ts"
// 1. `astro:content`에서 유틸리티 가져오기
import { defineCollection, z } from 'astro:content';

// 2. 로더 가져오기
import { glob, file } from 'astro/loaders';

// 3. 컬렉션 정의
const blog = defineCollection({ /* ... */ });
const dogs = defineCollection({ /* ... */ });

// 4. 컬렉션을 등록하기 위해 단일 `collections` 객체 내보내기
export const collections = { blog, dogs };
```

### 컬렉션 `loader` 정의

Content Layer API를 사용하면 프로젝트에 로컬로 저장하든 원격으로 저장하든 콘텐츠를 가져올 수 있으며, `loader` 속성을 사용하여 데이터를 검색할 수 있습니다. 

#### 내장 로더

Astro는 로컬 콘텐츠를 가져오기 위한 [두 가지 내장 로더 함수](/ko/reference/content-loader-reference/#내장-로더) (`glob()` 및 `file()`)와 자체 로더를 구성하고 원격 데이터를 가져오기 위한 API에 대한 액세스를 제공합니다.

[`glob()` 로더](/ko/reference/content-loader-reference/#glob-로더)는 파일 시스템 어디에서나 Markdown, MDX, Markdoc, JSON, YAML 또는 TOML 파일 디렉터리에서 항목을 만듭니다. [micromatch](https://github.com/micromatch/micromatch#matching-features)에서 지원하는 glob 패턴을 사용하여 일치시킬 항목 파일의 `pattern`과 파일 위치의 기본 파일 경로를 받습니다. 각 항목의 `id`는 파일 이름으로부터 자동으로 생성됩니다. 항목당 파일이 하나씩 있을 때 이 로더를 사용합니다.

[`file()` 로더](/ko/reference/content-loader-reference/#file-로더)는 단일 로컬 파일에서 여러 항목을 생성합니다. 파일의 각 항목에는 고유한 `id` 키 속성이 있어야 합니다. 이 로더는 파일의 `base` 파일 경로를 인자로 받고 자동으로 분석할 수 없는 파일을 위해 선택적으로 [`parser` 함수](#parser-함수)를 인자로 받습니다. 데이터 파일을 객체 배열로 구문 분석할 수 있는 경우 이 로더를 사용합니다.

```ts  title="src/content.config.ts" {5,9}
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders'; // 레거시 API에서는 사용 불가능

const blog = defineCollection({
  loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
  schema: /* ... */
});
const dogs = defineCollection({
  loader: file("src/data/dogs.json"),
  schema: /* ... */ 
});

const probes = defineCollection({
  // `loader`는 문자열 패턴뿐만 아니라 여러 패턴의 배열도 허용합니다.
  // space-probes 디렉터리에서 "voyager-"로 시작하는 파일을 제외한 모든 Markdown 파일을 로드합니다.
  loader: glob({ pattern: ['*.md', '!voyager-*'], base: 'src/data/space-probes' }),
  schema: z.object({
    name: z.string(),
    type: z.enum(['Space Probe', 'Mars Rover', 'Comet Lander']),
    launch_date: z.date(),
    status: z.enum(['Active', 'Inactive', 'Decommissioned']),
    destination: z.string(),
    operator: z.string(),
    notable_discoveries: z.array(z.string()),
  }),
});

export const collections = { blog, dogs, probes };
```

##### `parser` 함수

`file()` 로더는 `parser` 함수를 정의하는 두 번째 인수를 받습니다. 이를 통해 사용자 정의 구문 분석기(예: `csv-parse`)를 지정하여 파일 콘텐츠에서 컬렉션을 생성할 수 있습니다.

`file()` 로더는 JSON 및 YAML 파일에서 단일 객체 배열을 자동으로 감지하고 구문 분석하며 (파일 확장자에 따라), TOML 파일의 각 최상위 테이블을 독립된 항목으로 취급합니다. 기본적으로 이러한 파일 형식을 지원하며, [중첩된 JSON 문서](#중첩된-json-문서)가 없는 한 `parser`가 필요하지 않습니다. `.csv`와 같은 다른 파일을 사용하려면 파서 함수를 만들어야 합니다.

다음 예시는 CSV 파서를 가져온 다음 파일 경로와 `parser` 함수를 모두 `file()` 로더에 전달하여 프로젝트에 `cats` 컬렉션을 로드하는 방법을 보여줍니다.

```typescript title="src/content.config.ts"
import { defineCollection } from "astro:content";
import { file } from "astro/loaders";
import { parse as parseCsv } from "csv-parse/sync";

const cats = defineCollection({
  loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
});
```

###### 중첩된 `.json` 문서

`parser` 인수를 사용하면 중첩된 JSON 문서에서 단일 컬렉션을 로드할 수도 있습니다. 예를 들어 이 JSON 파일에는 여러 컬렉션이 포함되어 있습니다:

```json title="src/data/pets.json"
{"dogs": [{}], "cats": [{}]}
```

각 컬렉션에 대해 사용자 정의 `parser`를 `file()` 로더에 전달하여 이러한 컬렉션을 분리할 수 있습니다:

```typescript title="src/content.config.ts"
const dogs = defineCollection({
  loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).dogs })
});
const cats = defineCollection({
  loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).cats })
});
```

#### 사용자 지정 로더 빌드

사용자 지정 로더를 빌드하여 CMS, 데이터베이스, API 엔드포인트 등 모든 데이터 소스에서 원격 콘텐츠를 가져올 수 있습니다.

로더를 사용해 데이터를 가져오면 원격 데이터에서 컬렉션이 자동으로 만들어집니다. 이렇게 하면 `getCollection()` 및 `render()`와 같이 데이터를 쿼리하고 표시하는 컬렉션 전용 API 헬퍼와 스키마 유효성 검사 등 로컬 컬렉션의 모든 이점을 누릴 수 있습니다.

:::tip
[Astro 통합 디렉터리](https://astro.build/integrations/?search=&categories%5B%5D=loaders)에서 커뮤니티 구축 및 타사 로더를 찾아보세요.
:::

##### 인라인 로더

컬렉션 내부에서 로더를 인라인으로 정의하여 항목 배열을 반환하는 비동기 함수로 정의할 수 있습니다.

이는 데이터를 불러와 저장하는 방식을 수동으로 제어할 필요가 없는 로더에 유용합니다. 로더가 호출될 때마다 스토어를 비우고 모든 항목을 다시 불러옵니다.

```ts title="src/content.config.ts"
const countries = defineCollection({
  loader: async () => {
    const response = await fetch("https://restcountries.com/v3.1/all");
    const data = await response.json();
    // id 속성을 가진 항목들의 배열을 반환하거나, ID를 키로 하고 항목을 값으로 하는 객체를 반환해야 합니다.
    return data.map((country) => ({
      id: country.cca3,
      ...country,
    }));
  },
  schema: /* ... */
});
```

반환된 항목들은 컬렉션에 저장되며 `getCollection()` 및 `getEntry()` 함수를 사용하여 조회할 수 있습니다.

##### 로더 객체

로딩 프로세스를 더 세밀하게 제어하려면 Content Loader API를 사용하여 로더 객체를 생성할 수 있습니다. 예를 들어, `load` 메서드에 직접 접근할 수 있어 항목을 점진적으로 업데이트하거나 필요할 때만 스토어를 비우는 로더를 만들 수 있습니다.

Astro 통합이나 Vite 플러그인을 만드는 것처럼, [로더를 NPM 패키지로 배포](/ko/reference/publish-to-npm/)하여 다른 사람들이 자신의 프로젝트에서 사용할 수 있게 할 수 있습니다.

<ReadMore>전체 [Content Loader API](/ko/reference/content-loader-reference/)와 자체 로더를 구축하는 방법에 대한 예시를 참조하세요.</ReadMore>

### 컬렉션 스키마 정의

스키마는 Zod 유효성 검사를 통해 컬렉션의 프런트매터나 항목 데이터의 일관성을 강제합니다. 스키마는 데이터를 참조하거나 쿼리할 때 데이터가 예측 가능한 형태로 존재함을 **보장합니다**. 만약 어떤 파일이 컬렉션 스키마를 위반하면, Astro는 도움이 되는 오류 메시지를 표시합니다.

스키마는 또한 Astro의 자동 TypeScript 타입 생성 기능을 제공합니다. 컬렉션에 스키마를 정의하면 Astro는 자동으로 TypeScript 인터페이스를 생성하고 적용합니다. 그 결과 컬렉션을 쿼리할 때 속성 자동 완성과 타입 검사를 포함한 완전한 TypeScript 지원을 받을 수 있습니다.

:::tip
Astro가 새 스키마 또는 업데이트된 스키마를 인식하려면 개발 서버를 다시 시작하거나 [콘텐츠 레이어 동기화](/ko/reference/cli-reference/#astro-dev) (<code>s + enter</code>)를 통해 `astro:content` 모듈을 정의해야 할 수도 있습니다.
:::

컬렉션 항목의 모든 프런트매터나 데이터 속성은 Zod 데이터 타입을 사용하여 정의되어야 합니다:

```ts title="src/content.config.ts" {6-11,15-19}
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders'; // 레거시 API에서는 사용 불가능

const blog = defineCollection({
  loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    updatedDate: z.coerce.date().optional(),
  })
});
const dogs = defineCollection({
  loader: file("src/data/dogs.json"),
  schema: z.object({
    id: z.string(),
    breed: z.string(),
    temperament: z.array(z.string()),
  }),
});

export const collections = { blog, dogs };
```

#### Zod를 사용한 데이터 타입 정의

Astro는 콘텐츠 스키마를 위해 [Zod](https://github.com/colinhacks/zod)를 사용합니다. Astro는 Zod를 통해 컬렉션의 모든 파일의 데이터를 검증하고, 프로젝트에서 콘텐츠를 쿼리할 때 자동으로 TypeScript 타입을 제공할 수 있습니다.

Astro에서 Zod를 사용하려면 `"astro:content"`에서 `z` 유틸리티를 가져옵니다. 이는 Zod 라이브러리를 다시 내보낸 것으로, Zod의 모든 기능을 지원합니다.

```ts
// 예시: 자주 사용되는 Zod 데이터 타입 치트 시트
import { z, defineCollection } from 'astro:content';

defineCollection({
  schema: z.object({
    isDraft: z.boolean(),
    title: z.string(),
    sortOrder: z.number(),
    image: z.object({
      src: z.string(),
      alt: z.string(),
    }),
    author: z.string().default('Anonymous'),
    language: z.enum(['en', 'es']),
    tags: z.array(z.string()),
    footnote: z.string().optional(),

    // YAML에서 따옴표로 감싸지 않은 날짜는 Date 객체로 해석됩니다
    publishDate: z.date(), // e.g. 2024-09-17

    // 날짜 문자열(예: "2022-07-08")을 Date 객체로 변환
    updatedDate: z.string().transform((str) => new Date(str)),

    authorContact: z.string().email(),
    canonicalURL: z.string().url(),
  })
})
```

<ReadMore>[Zod의 README](https://github.com/colinhacks/zod)에서 Zod의 작동 방식과 사용 가능한 기능에 대한 전체 문서를 확인하세요.</ReadMore>

##### Zod 스키마 메서드

모든 [Zod 스키마 메서드](https://zod.dev/?id=schema-methods)(예: `.parse()`, `.transform()`)는 일부 제한사항과 함께 사용할 수 있습니다. 특히 `image().refine()`을 사용한 이미지의 사용자 정의 유효성 검사는 지원되지 않습니다.

#### 컬렉션 참조 정의

컬렉션 항목은 다른 관련 항목을 "참조"할 수도 있습니다.

Collections API의 [`reference()` 함수](/ko/reference/modules/astro-content/#reference)를 사용하면 컬렉션 스키마의 속성을 다른 컬렉션의 항목으로 정의할 수 있습니다. 예를 들어, 모든 `space-shuttle` 항목에 `pilot` 컬렉션의 스키마를 사용하여 타입 검사, 자동 완성, 유효성 검증을 수행하는 `pilot` 속성을 포함하도록 요구할 수 있습니다.

일반적인 예시로는 JSON으로 저장된 재사용 가능한 작성자 프로필을 참조하거나, 같은 컬렉션에 저장된 관련 게시물 URL을 참조하는 블로그 게시물이 있습니다:

```ts title="src/content.config.ts"
import { defineCollection, reference, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
  loader: glob({ pattern: '**/[^_]*.md', base: "./src/data/blog" }),
  schema: z.object({
    title: z.string(),
    // `authors` 컬렉션에서 `id`로 단일 작성자 참조
    author: reference('authors'),
    // `blog` 컬렉션에서 `slug`로 관련 게시물 배열 참조
    relatedPosts: z.array(reference('blog')),
  })
});

const authors = defineCollection({
  loader: glob({ pattern: '**/[^_]*.json', base: "./src/data/authors" }),
  schema: z.object({
    name: z.string(),
    portfolio: z.string().url(),
  })
});

export const collections = { blog, authors };
```

이 예시 블로그 게시물은 관련 게시물들의 `id`와 게시물 작성자의 `id`를 지정합니다:

```yaml title="src/data/blog/welcome.md"
---
title: "Welcome to my blog"
author: ben-holmes # `src/data/authors/ben-holmes.json` 참조
relatedPosts:
- about-me # `src/data/blog/about-me.md` 참조
- my-year-in-review # `src/data/blog/my-year-in-review.md` 참조
---
```

이러한 참조는 `collection` 키와 `id` 키를 포함하는 객체로 변환되어 [템플릿에서 쉽게 쿼리](/ko/guides/content-collections/#참조된-데이터에-액세스)할 수 있습니다.

### 사용자 지정 ID 정의

Markdown, MDX, Markdoc 또는 JSON 파일에 `glob()` 로더를 사용할 때, 모든 콘텐츠 항목의 [`id`](/ko/reference/modules/astro-content/#id)는 콘텐츠 파일 이름을 기반으로 URL 친화적인 형식으로 자동 생성됩니다. 이 `id`는 컬렉션에서 직접 항목을 쿼리할 때 사용됩니다. 또한 콘텐츠로부터 새로운 페이지와 URL을 만들 때도 유용합니다.

파일의 프런트매터나 JSON 파일의 데이터 객체에 `slug` 속성을 추가하여 항목의 자동 생성된 `id`를 재정의할 수 있습니다. 이는 다른 웹 프레임워크의 “permalink” 기능과 유사합니다.

```md title="src/blog/1.md" {3}
---
title: My Blog Post
slug: my-custom-id/supports/slashes
---
Your blog post content here.
```

```json title="src/categories/1.json" {3}
{
  "title": "My Category",
  "slug": "my-custom-id/supports/slashes",
  "description": "Your category description here."
}
```

## 컬렉션 쿼리

Astro는 컬렉션을 쿼리하고 하나 (또는 여러 개)의 콘텐츠 항목을 반환하는 헬퍼 함수를 제공합니다.

- [`getCollection()`](/ko/reference/modules/astro-content/#getcollection)은 전체 컬렉션을 가져와서 항목 배열을 반환합니다.
- [`getEntry()`](/ko/reference/modules/astro-content/#getentry)는 컬렉션에서 단일 항목을 가져옵니다.

이들은 고유한 `id`, 정의된 모든 속성을 포함한 `data` 객체, 그리고 Markdown, MDX 또는 Markdoc 문서의 컴파일되지 않은 원시 본문을 포함하는 `body`를 가진 항목들을 반환합니다.

```js
import { getCollection, getEntry } from 'astro:content';

// 컬렉션의 모든 항목을 가져옵니다.
// 컬렉션의 이름을 인자로 필요로 합니다.
const allBlogPosts = await getCollection('blog');

// 컬렉션에서 단일 항목을 가져옵니다.
// 컬렉션 이름과 `id`가 필요합니다
const poodleData = await getEntry('dogs', 'poodle');

```

생성된 컬렉션의 정렬 순서는 비결정적이며 플랫폼에 따라 다릅니다. 즉, `getCollection()`을 호출할 때 항목을 특정 순서 (예: 날짜별로 정렬된 블로그 게시물)로 반환해야 하는 경우, 컬렉션 항목을 직접 정렬해야 합니다.

```astro title="src/pages/blog.astro"
---
import { getCollection } from 'astro:content';

const posts = (await getCollection('blog')).sort(
  (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
);
---
```

<ReadMore>[`CollectionEntry` 타입](/ko/reference/modules/astro-content/#collectionentry)이 반환하는 전체 속성 목록을 확인하세요.</ReadMore>

### Astro 템플릿에서 콘텐츠 사용

컬렉션을 쿼리한 후에는 Astro 컴포넌트 템플릿에서 각 항목의 콘텐츠에 직접 접근할 수 있습니다. 예를 들어, `data` 속성을 사용하여 항목의 프런트매터 정보를 표시하는 블로그 게시물 링크 목록을 만들 수 있습니다.

```astro title="src/pages/index.astro"
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
<h1>My posts</h1>
<ul>
  {posts.map(post => (
    <li><a href={`/blog/${post.id}`}>{post.data.title}</a></li>
  ))}
</ul>
```
#### 본문 콘텐츠 렌더링

쿼리가 완료되면 [`render()`](/ko/reference/modules/astro-content/#render) 함수 속성을 사용하여 Markdown과 MDX 항목을 HTML로 렌더링할 수 있습니다. 이 함수를 호출하면 `<Content />` 컴포넌트와 렌더링된 모든 제목 목록을 포함한 HTML 콘텐츠에 접근할 수 있습니다.

```astro title="src/pages/blog/post-1.astro" {5,8}
---
import { getEntry, render } from 'astro:content';

const entry = await getEntry('blog', 'post-1');
if (!entry) {
  // 에러 처리, 예시:
  throw new Error('Could not find blog post 1');
}
const { Content, headings } = await render(entry);
---
<p>Published on: {entry.data.published.toDateString()}</p>
<Content />
```

<ReadMore>MDX 항목을 다룰 때, [사용자 정의 컴포넌트를 `<Content />`에 전달](/ko/guides/integrations-guide/mdx/#components를-mdx-콘텐츠로-전달하기)하여 HTML 요소를 사용자 정의 대안으로 대체할 수도 있습니다.</ReadMore>

#### 콘텐츠를 props로 전달

컴포넌트는 컬렉션 항목 전체를 prop으로 전달할 수도 있습니다.

TypeScript를 사용하여 컴포넌트의 props를 올바르게 타이핑하기 위해 [`CollectionEntry`](/ko/reference/modules/astro-content/#collectionentry) 유틸리티를 사용할 수 있습니다. 이 유틸리티는 컬렉션 스키마의 이름과 일치하는 문자열 인자를 받아 해당 컬렉션 스키마의 모든 속성을 상속합니다.

```astro title="src/components/BlogCard.astro" /CollectionEntry(?:<.+>)?/
---
import type { CollectionEntry } from 'astro:content';
interface Props {
  post: CollectionEntry<'blog'>;
}

// `post`는 'blog' 컬렉션 스키마 타입과 일치합니다
const { post } = Astro.props;
---
```

### 컬렉션 쿼리 필터링

`getCollection()`은 항목의 `id`나 `data` 속성을 기반으로 쿼리를 필터링할 수 있는 선택적 "filter" 콜백을 받습니다.

이를 통해 원하는 모든 콘텐츠 조건으로 필터링할 수 있습니다. 예를 들어, `draft` 같은 속성으로 필터링하여 초안 상태인 블로그 게시물이 게시되는 것을 방지할 수 있습니다:

```js
// 예시: `draft: true`인 콘텐츠 항목 필터링
import { getCollection } from 'astro:content';
const publishedBlogEntries = await getCollection('blog', ({ data }) => {
  return data.draft !== true;
});
```

개발 환경에서는 접근 가능하지만 프로덕션 빌드에서는 제외되는 초안 페이지를 만들 수 있습니다:

```js
// 예시: 프로덕션용 빌드 시에만 `draft: true`인 콘텐츠 항목 필터링
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog', ({ data }) => {
  return import.meta.env.PROD ? data.draft !== true : true;
});
```

필터 인자는 컬렉션 내에서 중첩된 디렉터리로도 필터링을 할 수 있습니다. `id`가 전체 중첩 경로를 포함하고 있기 때문에, 각 `id`의 시작 부분으로 필터링하여 특정 중첩 디렉터리의 항목만 반환할 수 있습니다:

```js
// 예시: 컬렉션의 하위 디렉터리로 항목 필터링
import { getCollection } from 'astro:content';
const englishDocsEntries = await getCollection('docs', ({ id }) => {
  return id.startsWith('en/');
});
```

### 참조된 데이터에 액세스

[스키마에 정의된 모든 참조](/ko/guides/content-collections/#컬렉션-참조-정의)는 컬렉션 항목을 먼저 쿼리한 후 별도로 쿼리해야 합니다. [`reference()` 함수](/ko/reference/modules/astro-content/#reference)는 참조를 `collection`과 `id`를 키로 가진 객체로 변환하므로, `getEntry()` 함수를 사용하여 단일 참조 항목을 반환하거나, `getEntries()`를 사용하여 반환된 `data` 객체에서 참조된 여러 항목을 검색할 수 있습니다.

```astro title="src/pages/blog/welcome.astro"
---
import { getEntry, getEntries } from 'astro:content';

const blogPost = await getEntry('blog', 'welcome');

// 단일 참조 처리 (예: `{collection: "authors", id: "ben-holmes"}`)
const author = await getEntry(blogPost.data.author);
// 참조 배열 처리
// (예: `[{collection: "blog", id: "about-me"}, {collection: "blog", id: "my-year-in-review"}]`)
const relatedPosts = await getEntries(blogPost.data.relatedPosts);
---

<h1>{blogPost.data.title}</h1>
<p>Author: {author.data.name}</p>

<!-- ... -->

<h2>You might also like:</h2>
{relatedPosts.map(post => (
  <a href={post.id}>{post.data.title}</a>
))}
```

## 콘텐츠로부터 라우트 생성

콘텐츠 컬렉션은 `src/pages/` 디렉터리 외부에 저장됩니다. 이는 기본적으로 컬렉션 항목에 대한 페이지나 라우트가 생성되지 않는다는 것을 의미합니다.

개별 블로그 게시물과 같이 각 컬렉션 항목에 대한 HTML 페이지를 생성하려면 새로운 [동적 라우트](/ko/guides/routing/#동적-라우트)를 수동으로 생성해야 합니다. 동적 라우트는 들어오는 요청 매개변수(예: `src/pages/blog/[...slug].astro`의 `Astro.params.slug`)를 각 페이지에 맞는 올바른 항목을 가져오는 데 사용합니다.

라우트 생성을 위한 정확한 방법은 페이지가 미리 렌더링되는지(기본값) 또는 서버에서 필요할 때 렌더링되는지에 따라 달라집니다.

### 정적 출력을 위한 빌드(기본값)

정적 웹사이트를 빌드하는 경우(Astro의 기본 동작), 빌드 시 단일 페이지 컴포넌트(예: `src/pages/[slug]`)에서 여러 페이지를 생성하기 위해 [`getStaticPaths()`](/ko/reference/routing-reference/#getstaticpaths) 함수를 사용하세요.

`getStaticPaths()`에서 `getCollection()`을 호출하여 정적 라우트 빌드에 필요한 컬렉션 데이터를 사용할 수 있습니다. 그런 다음 각 콘텐츠 항목의 `id` 속성을 사용하여 개별 URL 경로를 생성합니다. 각 페이지는 전체 컬렉션 항목을 prop으로 전달받아 [페이지 템플릿에서 사용](#astro-템플릿에서-콘텐츠-사용)할 수 있습니다.

```astro title="src/pages/posts/[id].astro" "{ id: post.id }" "{ post }"
---
import { getCollection, render } from 'astro:content';
// 1. 모든 컬렉션 항목에 대한 새로운 경로 생성
export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map(post => ({
    params: { id: post.id },
    props: { post },
  }));
}
// 2. 템플릿에서는 prop으로부터 항목을 직접 가져올 수 있음
const { post } = Astro.props;
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />
```

`blog` 컬렉션의 모든 항목에 대해 페이지 라우트가 생성됩니다. 예를 들어, `src/blog/hello-world.md`에 있는 항목의 `id`는 `hello-world`가 되며, 따라서 최종 URL은 `/posts/hello-world/`가 됩니다.

:::note
`/` 문자가 포함된 커스텀 슬러그를 사용하여 여러 경로 세그먼트가 있는 URL을 생성하는 경우, 이 동적 라우팅 페이지의 `.astro` 파일 이름에 [나머지 매개변수(예: `[...slug]`)](/ko/guides/routing/#나머지-매개변수)를 사용해야 합니다.
:::

### 서버 출력(SSR) 빌드 

동적 웹사이트를 만드는 경우(Astro의 SSR 지원 사용), 빌드 과정에서 경로를 미리 생성할 필요가 없습니다. 대신, 페이지에서 요청을 검사하여(`Astro.request` 또는 `Astro.params` 사용) `slug`를 찾은 다음 [`getEntry()`](/ko/reference/modules/astro-content/#getentry)를 사용하여 가져오면 됩니다.

```astro title="src/pages/posts/[id].astro"
---
import { getEntry, render } from "astro:content";
// 1. 들어오는 서버 요청에서 slug 가져오기
const { id } = Astro.params;
if (id === undefined) {
	return Astro.redirect("/404");
}
// 2. 요청의 slug를 사용하여 항목 직접 조회
const post = await getEntry("blog", id);
// 3. 항목이 존재하지 않으면 리디렉션
if (post === undefined) {
	return Astro.redirect("/404");
}
// 4. 템플릿에서 항목을 HTML로 렌더링
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />
```

:::tip
[GitHub의 블로그 튜토리얼 데모 코드](https://github.com/withastro/blog-tutorial-demo/tree/content-collections/src/pages)의 `src/pages/` 폴더를 살펴보면 블로그 게시물 목록, 태그 페이지 등과 같은 블로그 기능을 위해 컬렉션으로부터 페이지를 생성하는 전체 예시를 확인할 수 있습니다!
:::

## 컬렉션 JSON 스키마

<p><Since v="4.13.0" /></p>

Astro는 컬렉션용 [JSON 스키마](https://json-schema.org/) 파일을 자동으로 생성하며, 이를 편집기에서 사용하면 데이터 파일에 대한 IntelliSense 및 타입 검사를 받을 수 있습니다.

프로젝트의 각 컬렉션에 대해 JSON 스키마 파일이 생성되어 `.astro/collections/` 디렉터리에 출력됩니다.
예를 들어, `authors`와 `posts`라는 두 컬렉션이 있다면, Astro는 `.astro/collections/authors.schema.json`와 `.astro/collections/posts.schema.json`을 생성합니다.

### JSON 파일에서 JSON 스키마 사용하기

JSON 파일에서 `$schema` 필드를 설정하여 Astro가 생성한 스키마를 직접 지정할 수 있습니다.
값은 데이터 파일에서 스키마까지의 상대 파일 경로여야 합니다.
다음은 `src/data/authors/`에 있는 데이터 파일이 `authors` 컬렉션용으로 생성된 스키마를 사용하는 예시입니다.

```json title="src/data/authors/armand.json" ins={2}
{
  "$schema": "../../../.astro/collections/authors.schema.json",
  "name": "Armand",
  "skills": ["Astro", "Starlight"]
}
```

#### VS Code에서 JSON 파일 그룹에 스키마 사용하기

VS Code에서 [`json.schemas` 설정](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings)을 사용하여 컬렉션 내 모든 파일에 적용할 스키마를 구성할 수 있습니다.
다음은 `src/data/authors/` 디렉터리 내 모든 파일이 `authors` 컬렉션용으로 생성된 스키마를 사용하는 예시입니다.

```json
{
  "json.schemas": [
    {
      "fileMatch": ["/src/data/authors/**"],
      "url": "./.astro/collections/authors.schema.json"
    }
  ]
}
```

### VS Code에서 YAML 파일의 스키마 사용하기

VS Code에서 [Red Hat YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) 확장 기능을 사용하면 YAML 파일에서 JSON 스키마를 사용할 수 있습니다.
이 확장 기능을 설치하면 특수 주석 구문을 사용하여 YAML 파일에서 스키마를 참조할 수 있습니다.

```yaml title="src/data/authors/armand.yml" ins={1}
# yaml-language-server: $schema=../../../.astro/collections/authors.schema.json
name: Armand
skills:
  - Astro
  - Starlight
```

#### VS Code에서 YAML 파일 그룹에 스키마 사용하기

Red Hat YAML 확장 기능을 사용하면 `yaml.schemas` 설정을 통해 컬렉션 내 모든 YAML 파일에 적용할 스키마를 구성할 수 있습니다.
다음은 `src/data/authors/` 디렉터리 내 모든 YAML 파일이 `authors` 컬렉션용으로 생성된 스키마를 사용하는 예시입니다.

```json
{
  "yaml.schemas": {
    "./.astro/collections/authors.schema.json": ["/src/content/authors/*.yml"]
  }
}
```

자세한 내용은 Red Hat YAML 확장 기능 문서의 [“Associating schemas”](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml#associating-schemas)를 참조하세요.

## 컬렉션 생성이 필요한 경우

관련된 데이터나 콘텐츠가 공통 구조를 공유하는 그룹이 있을 때마다 [컬렉션을 생성](#컬렉션-정의)할 수 있습니다.

컬렉션 사용의 주요 이점은 다음과 같습니다:

- 개별 항목이 "올바른지" 또는 "완전한지" 검증하여 프로덕션에서의 오류를 방지할 수 있는 공통 데이터 형태를 정의할 수 있습니다.
- 페이지에서 콘텐츠를 가져와 렌더링할 때 직관적인 쿼리가 가능하도록 설계된 콘텐츠 중심의 API를 제공합니다(예: `import.meta.glob()` 대신 `getCollection()` 사용).
- 콘텐츠를 가져오기 위한 [Content Loader API](/ko/reference/content-loader-reference/)는 내장 로더와 저수준 API 접근을 모두 제공합니다. 여러 서드파티 및 커뮤니티에서 제작한 로더를 사용할 수 있으며, 원하는 곳에서 데이터를 가져올 수 있는 자체 커스텀 로더를 만들 수도 있습니다.
- 성능과 확장성이 뛰어납니다. Content Layer API를 통해 빌드 간에 데이터를 캐시할 수 있으며, 수만 개의 콘텐츠 항목도 처리할 수 있습니다.

다음과 같은 경우에 [데이터를 컬렉션으로 정의](#컬렉션-정의)하세요:

- 동일한 구조(예: 같은 프런트매터 속성을 가진 Markdown 블로그 게시물들)를 공유하는 여러 파일이나 데이터를 정리해야 하는 경우
- CMS와 같이 원격에 저장된 기존 콘텐츠가 있고, `fetch()`나 SDK 대신 컬렉션 헬퍼 함수와 Content Layer API를 활용하고 싶은 경우
- 수만 개의 연관된 데이터를 가져와야 하고, 대규모 처리가 가능한 쿼리와 캐싱 방법이 필요한 경우

### 컬렉션 생성이 불필요한 경우

컬렉션은 **동일한 속성을 공유해야 하는 여러 콘텐츠가 있을 때** 우수한 구조와 안정성, 그리고 체계를 제공합니다.

다음과 같은 경우에는 컬렉션이 **적절한 해결책이 아닐 수 있습니다**:

- 하나 또는 소수의 서로 다른 페이지만 있는 경우. 대신 `src/pages/about.astro`와 같이 콘텐츠를 직접 포함하는 [개별 페이지 컴포넌트를 만드는 것](/ko/basics/astro-pages/)을 고려하세요.
- PDF와 같이 Astro가 처리하지 않는 파일을 표시하는 경우. 대신 이러한 정적 자산을 프로젝트의 [`public/` 디렉터리](/ko/basics/project-structure/#public)에 두세요.
- 데이터 소스가 가져오기를 위한 자체 SDK/클라이언트 라이브러리를 보유하고 있으며, 이 라이브러리가 콘텐츠 로더와 호환되지 않거나 콘텐츠 로더를 제공하지 않아 해당 라이브러리를 직접 사용하는 것을 선호하는 경우
- 실시간으로 업데이트가 필요한 API를 사용하고 있는 경우. 콘텐츠 컬렉션은 빌드 시에만 업데이트되므로, 실시간 데이터가 필요한 경우에는 [요청 시 렌더링](/ko/guides/on-demand-rendering/)을 통해 [파일 가져오기](/ko/guides/imports/#import-구문) 또는 [데이터 가져오기](/ko/guides/data-fetching/)와 같은 다른 방법을 사용하세요.
